// Fill out your copyright notice in the Description page of Project Settings.



#include <UI/Widget/SSlateDemoMainWindowWidget.h>
#include "SlateOptMacros.h"
#include "Widgets/Input/SButton.h"
#include "Framework/Notifications/NotificationManager.h"
#include "Widgets/Docking/SDockTab.h"
#include "SlateFwd.h"
#include "Blueprint/UserWidget.h"
#include "Kismet/GameplayStatics.h"
#include "Widgets/SBoxPanel.h"
#include "Widgets/Colors/SColorBlock.h"
#include "UI/Widget/SSlateDemoSlateBaseWidget.h"
#include "UI/Widget/SSlateDemoSlateAdvancedWidget.h"
#include "SSlateDemoSlateDrawPaintWidget.h"
#include "Engine/GameEngine.h"
#include <Framework/Application/SWindowTitleBar.h>
#include <UI/Widget/SSlateDemoOtherWidget.h>
#define GAMEENGINE_WINDOW true //利用GameEngine窗口作为根窗口进行绘制 要修改UE4对应的源码,教程请看https://zhuanlan.zhihu.com/p/374158119

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlateDemoMainWindowWidget::Construct(const FArguments& InArgs)
{
#if GAMEENGINE_WINDOW
	UGameEngine* engine = Cast<UGameEngine>(GEngine);
	CreateMainWindow();
	ChildSlot
		[
		/*	SNew(SVerticalBox)
			+ SVerticalBox::Slot().AutoHeight()
			[
				SNew(SWindowTitleBar, engine->GameViewportWindow.Pin().ToSharedRef(), nullptr, EHorizontalAlignment::HAlign_Center)
			]
			+ SVerticalBox::Slot()
			[*/
				MainFrameContent.ToSharedRef()
			//]

		];
#else
	ChildSlot
	[
		CreateMainWindow()
	];
#endif
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

TSharedRef<SWindow> SSlateDemoMainWindowWidget::CreateMainWindow()
{

#if GAMEENGINE_WINDOW//利用GameEngine窗口作为根窗口进行绘制,此种方案修改修改源码相关教程请参考
	UGameEngine* engine = Cast<UGameEngine>(GEngine);
	TSharedRef<SWindow> RootWindow = engine->GameViewportWindow.Pin().ToSharedRef();

	FGlobalTabmanager::Get()->RegisterTabSpawner("UMGToSlateDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainUMGToSlateTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateBaseDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateBaseTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateAdvancedDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateAdvancedDemoTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateDrawPaintDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateDrawPaintDemoTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateOtherDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainOtherDemoTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateScenceDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainScenceTab));

	FGlobalTabmanager::Get()->SetRootWindow(RootWindow);
	FSlateNotificationManager::Get().SetRootWindow(RootWindow);

	TSharedRef<FTabManager::FLayout> TabLayout =
		FTabManager::NewLayout("SlateDemo")
		->AddArea
		(
			// main window
			FTabManager::NewPrimaryArea()
			->Split
			(
				FTabManager::NewStack()
				->AddTab("UMGToSlateDemo", ETabState::OpenedTab)
				->AddTab("SlateBaseDemo", ETabState::OpenedTab)
				->AddTab("SlateAdvancedDemo", ETabState::OpenedTab)
				->AddTab("SlateDrawPaintDemo", ETabState::OpenedTab)
				->AddTab("SlateOtherDemo", ETabState::OpenedTab)
				->AddTab("SlateScenceDemo", ETabState::OpenedTab)
			)
		);
	MainFrameContent = FGlobalTabmanager::Get()->RestoreFrom(TabLayout, RootWindow, false, EOutputCanBeNullptr::IfNoOpenTabValid);
	RootWindow->SetContent(MainFrameContent.ToSharedRef());
	TSharedPtr<SDockTab> MainTab;
	MainTab = FGlobalTabmanager::Get()->InvokeTab(FTabId("SlateAdvancedDemo"));


	FGlobalTabmanager::Get()->SetMainTab(MainTab.ToSharedRef());
	RootWindow->ShowWindow();
	return RootWindow;
#else//在GameEngine窗口中嵌入新建的窗口进行绘制,这种情况有BUG,当把TAB标签页拖拽成窗口时,此新窗口就会出现未响应的状态

	TSharedRef<SWindow> MainWindow = SNew(SWindow)
		.Type(EWindowType::Normal)															// 窗口类型
		//.Style()																			// 样式
		//.Title(FText::FromString("SlateDemo"))												// 标题
		.bDragAnywhere(true)																// 拖动到任何地方
		.AutoCenter(EAutoCenter::PreferredWorkArea)											// 自动居中：首选工作区域
		.ScreenPosition(FVector2D(0, 0))													// 窗口最初位于屏幕空间的位置
		.ClientSize(FVector2D(1100, 720))													// 窗口大小
		.AdjustInitialSizeAndPositionForDPIScale(true)									// 初始位置和大小自动调整适应DPI缩放
		//.SupportsTransparency()															// 窗口是否支持透明
		//.InitialOpacity(1.0f)																// 窗口初始不透明度
		//.IsInitiallyMaximized(false)														// 窗口初始最大化
		.IsInitiallyMinimized(true)															// 窗口初始最小化
		.SizingRule(ESizingRule::UserSized)													// 窗口大小如何确定：用户调整大小
		//.IsPopupWindow(false)																// 是否为Popup窗口
		//.IsTopmostWindow(true)															// 是否始终位于所有其他窗口之上
		.FocusWhenFirstShown(true)															// 该窗口是否应该在显示后立即聚焦
		.ActivationPolicy(EWindowActivationPolicy::Always)									// 这个窗口在显示时应该什么时候被激活:总是激活
		.UseOSWindowBorder(false)															// 使用默认系统查找窗口边界
		.HasCloseButton(true)																// 这个窗口有关闭按钮吗
		.SupportsMaximize(true)																// 这个窗口可以最大化吗
		.SupportsMinimize(true)																// 这个窗口可以最小化吗
		.ShouldPreserveAspectRatio(true)													// 当用户调整大小时，该窗口是否应保持其长宽比
		.MinWidth(1100.f)																	// 此窗口的最小宽度可以以桌面像素为单位
		.MinHeight(720.f)																	// 此窗口的最小高度可以以桌面像素为单位
		//.MaxWidth(2000.f)																	// 此窗口的最大宽度可以以桌面像素为单位
		//.MaxHeight(1000.f)																// 此窗口的最大高度可以以桌面像素为单位
		.CreateTitleBar(true)																// 是否创建标题栏
		.SaneWindowPlacement(true)															// 如果窗口出现在屏幕外，或者太大，将强制现实约束窗口
		.LayoutBorder(FMargin(5.f))															// 窗口边缘填充
		.UserResizeBorder(FMargin(5.f));													// 窗口边缘周围的边距，用户可以通过它来调整窗口的大小
		//.bManualManageDPI(true)															// 是否窗口自行处理DPI缩放

	//先卸载避免重复加载
	FGlobalTabmanager::Get()->UnregisterTabSpawner("UMGToSlateDemo");
	FGlobalTabmanager::Get()->UnregisterTabSpawner("SlateBaseDemo");
	FGlobalTabmanager::Get()->UnregisterTabSpawner("SlateAdvancedDemo");
	FGlobalTabmanager::Get()->UnregisterTabSpawner("SlateDrawPaintDemo");

	FGlobalTabmanager::Get()->RegisterTabSpawner("UMGToSlateDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainUMGToSlateTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateBaseDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateBaseTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateAdvancedDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateAdvancedDemoTab));
	FGlobalTabmanager::Get()->RegisterTabSpawner("SlateDrawPaintDemo",
		FOnSpawnTab::CreateSP(this, &SSlateDemoMainWindowWidget::MainSlateDrawPaintDemoTab));
	FSlateApplication::Get().AddWindow(MainWindow, false);
	// 设置根窗口
	FGlobalTabmanager::Get()->SetRootWindow(MainWindow);
	// 提供一个窗口，所有通知都应该嵌套在该窗口下
	FSlateNotificationManager::Get().SetRootWindow(MainWindow);
	TSharedRef<FTabManager::FLayout> TabLayout =
		FTabManager::NewLayout("Main_Tab_Layle")
		->AddArea
		(
			// main window
			FTabManager::NewPrimaryArea()
			->Split
			(
				FTabManager::NewStack()
				->AddTab("UMGToSlateDemo", ETabState::OpenedTab)
				->AddTab("SlateBaseDemo", ETabState::OpenedTab)
				->AddTab("SlateAdvancedDemo", ETabState::OpenedTab)
				->AddTab("SlateDrawPaintDemo", ETabState::OpenedTab)
			)
		);
	TSharedPtr<SWidget> MainWindowContent;
	FGlobalTabmanager::Get()->RestoreFrom(TabLayout, MainWindow, false, EOutputCanBeNullptr::IfNoOpenTabValid);
	//// 创建主窗体上下文
	MainWindowContent = FGlobalTabmanager::Get()->RestoreFrom(TabLayout, MainWindow, false, EOutputCanBeNullptr::IfNoOpenTabValid);
	//// 将主窗体上下文设置到主窗体
	MainWindow->SetContent(MainWindowContent.ToSharedRef());
	TSharedPtr<SDockTab> MainTab;
	MainTab = FGlobalTabmanager::Get()->InvokeTab(FTabId("SlateAdvancedDemo"));//默认打开页面首先要显示的是哪一个TAB页
	// 初始化主窗口
	FGlobalTabmanager::Get()->SetMainTab(MainTab.ToSharedRef());

	return MainWindow;
#endif
}


/*
在没有详细教程之前,不建议在SLATE中直接嵌入UMG控件,因不知道相关的初始化操作,可能会造成未知的崩溃现象
在简单的嵌入蓝图界面时目前还没有发现崩溃现象
*/
TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainUMGToSlateTab(const FSpawnTabArgs& InArgs)
{
	UUserWidget* newUserWidget = nullptr;
	////SlateDemoUMGBP.SlateDemoUMGBP_C他的原名叫SlateDemoUMGBP但是在这里要写成这种样式"名字.名字_c"
	//这个蓝图继承自自己写的类USlateDemoUMGBPUserWidget
	UClass* SpecificBPClassFromCPlusPlus = LoadClass<UUserWidget>(NULL, TEXT("WidgetBlueprint'/Game/UI/SlateDemoUMGBP.SlateDemoUMGBP_C'"));
	if (SpecificBPClassFromCPlusPlus)
	{
		newUserWidget = CreateWidget<UUserWidget>(UGameplayStatics::GetPlayerController(GWorld->GetWorld(), 0), SpecificBPClassFromCPlusPlus);
		check(newUserWidget)
	}


	/*ubt = NewObject<UButton>();
	ubt->SetBackgroundColor(FLinearColor(FColor(102, 0, 102)));
	ubt->SetToolTipText(LOCTEXT("info", "在SLATE中使用UMG蓝图,和umg控件"));*/

	return SNew(SDockTab)//tab页
		.TabRole(ETabRole::PanelTab)//tab标签的样式,方形不可拖拽不可关闭
		.ToolTipText(FText::FromString(TEXT("这个标签页不是为了介绍控件,而是为了实现UGM蓝图,UMG控件,SLATE之间的相互嵌套使用")))
		.Label(FText::FromString(TEXT("在SLATE中使用UMG蓝图,和umg控件")))
	[
		SNew(SVerticalBox)
		+ SVerticalBox::Slot()
		.HAlign(HAlign_Left)
		.AutoHeight()
		[
			newUserWidget->TakeWidget()//这里是嵌入的UMG蓝图界面
		]
	//+ SVerticalBox::Slot()//在没有详细教程之前,不建议在SLATE中直接嵌入UMG控件,因不知道相关的初始化操作,可能会造成未知的崩溃现象
	//.HAlign(HAlign_Left)
	//.AutoHeight()
	//[
	//	ubt->TakeWidget()//这个是动态嵌入的UMG控件
	//]
	];
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainSlateAdvancedDemoTab(const FSpawnTabArgs& InArgs)//Slate高级控件
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("Slate高级控件")))
		[
			SNew(SSlateDemoSlateAdvancedWidget)
		];
	return ModelTab;
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainSlateBaseTab(const FSpawnTabArgs& InArgs)
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::MajorTab)
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("Slate基本控件")))
	[
		SNew(SSlateDemoSlateBaseWidget)
	];
	return ModelTab;
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainScenceTab(const FSpawnTabArgs& InArgs)
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::MajorTab)
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("场景")))
		[
			GEngine->GetGameViewportWidget().ToSharedRef()
		];
	return ModelTab;
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainOtherDemoTab(const FSpawnTabArgs& InArgs)//Slate高级控件
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("其他")))
		[
			SNew(SSlateDemoOtherWidget)
		];
	return ModelTab;
}


TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainSlateDrawPaintDemoTab(const FSpawnTabArgs& InArgs)//Slate高级控件
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("Slate绘图控件")))
		[
			SNew(SSlateDemoSlateDrawPaintWidget)
		];
	return ModelTab;
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainUMGToSlateTab2(const FSpawnTabArgs& InArgs)//Slate高级控件
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("aaaaaaa")))
		[
			SNew(SButton)
		];
	return ModelTab;
}

TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainSlateBaseTab2(const FSpawnTabArgs& InArgs)//Slate高级控件
{
	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("bbbbbb")))
		[
			SNew(SButton)
		];
	return ModelTab;
}



TSharedRef<SDockTab> SSlateDemoMainWindowWidget::MainSlateNewWindowTab(const FSpawnTabArgs& InArgs)//Slate高级控件
{



	TSharedRef<SWindow> MainWindow = SNew(SWindow)
		.Type(EWindowType::Normal)															// 窗口类型
		//.Style()																			// 样式
		//.Title(FText::FromString("SlateDemo"))												// 标题
		.bDragAnywhere(true)																// 拖动到任何地方
		.AutoCenter(EAutoCenter::PreferredWorkArea)											// 自动居中：首选工作区域
		.ScreenPosition(FVector2D(0, 0))													// 窗口最初位于屏幕空间的位置
		.ClientSize(FVector2D(1100, 720))													// 窗口大小
		.AdjustInitialSizeAndPositionForDPIScale(true)									// 初始位置和大小自动调整适应DPI缩放
		//.SupportsTransparency()															// 窗口是否支持透明
		//.InitialOpacity(1.0f)																// 窗口初始不透明度
		//.IsInitiallyMaximized(false)														// 窗口初始最大化
		.IsInitiallyMinimized(true)															// 窗口初始最小化
		.SizingRule(ESizingRule::UserSized)													// 窗口大小如何确定：用户调整大小
		//.IsPopupWindow(false)																// 是否为Popup窗口
		//.IsTopmostWindow(true)															// 是否始终位于所有其他窗口之上
		.FocusWhenFirstShown(true)															// 该窗口是否应该在显示后立即聚焦
		.ActivationPolicy(EWindowActivationPolicy::Always)									// 这个窗口在显示时应该什么时候被激活:总是激活
		.UseOSWindowBorder(false)															// 使用默认系统查找窗口边界
		.HasCloseButton(true)																// 这个窗口有关闭按钮吗
		.SupportsMaximize(true)																// 这个窗口可以最大化吗
		.SupportsMinimize(true)																// 这个窗口可以最小化吗
		.ShouldPreserveAspectRatio(true)													// 当用户调整大小时，该窗口是否应保持其长宽比
		.MinWidth(1100.f)																	// 此窗口的最小宽度可以以桌面像素为单位
		.MinHeight(720.f)																	// 此窗口的最小高度可以以桌面像素为单位
		//.MaxWidth(2000.f)																	// 此窗口的最大宽度可以以桌面像素为单位
		//.MaxHeight(1000.f)																// 此窗口的最大高度可以以桌面像素为单位
		.CreateTitleBar(false)																// 是否创建标题栏
		.SaneWindowPlacement(true)															// 如果窗口出现在屏幕外，或者太大，将强制现实约束窗口
		.LayoutBorder(FMargin(5.f))															// 窗口边缘填充
		.UserResizeBorder(FMargin(5.f));													// 窗口边缘周围的边距，用户可以通过它来调整窗口的大小
		//.bManualManageDPI(true)															// 是否窗口自行处理DPI缩放

	//先卸载避免重复加载

	
	// 添加窗口 不立即显示

	FSlateApplication::Get().AddWindow(MainWindow, false);
	// 设置根窗口





	TSharedRef<SDockTab> ModelTab = SNew(SDockTab)
		.TabRole(ETabRole::DocumentTab)//方形可拖拽可关闭
		.ContentPadding(FMargin(0))
		.Label(FText::FromString(TEXT("new window")))
		[
			MainWindow
		];
	return ModelTab;
}

